iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 5
0

前言

本章節會透過一個簡單的backend service來分析如何將其寫成Dockerfile,透過其Dockerfile生成Docker image,希望能拋磚引玉讓各位讀者能一窺其秘辛。

Preparation

這邊我準備了一個以uwsgi來啟動的flask web service,裡頭包含著一隻health check的api,啟動後路徑會為localhost:8100/v1/hc

所以目前repository的structure會長這樣

.
|____app
| |____app.py
| |____api
| | |____v1
| | | |____health.py
|____requirements.txt
|____Dockerfile
|____README.md
|____docker-entrypoint.sh
|____.gitignore
|____wsgi.py

這部分程式碼分為三部分:

  1. backend service: app.py, health.py, wsgi.py
  2. backend related packages: requirements.txt
  3. container related files: Dockerfile, docker-entrypoint.sh

Dockerfile

那現在我們來解析目錄下的Dockerfile吧

# Pull base image.
FROM ubuntu:18.04

# Set default WORKDIR in container
WORKDIR /usr/src/app

# Update the repository
COPY . .

# For log message in container
ENV PYTHONUNBUFFERED 1

# Install python 3.7
RUN apt-get update -y && \
    apt-get install -y python3.7 python3-pip python3.7-dev

# Install package requirements
COPY requirements.txt requirements.txt
RUN pip3 install --upgrade pip
RUN pip3 install -r requirements.txt

# EXPOSE 8100 port
EXPOSE 8100

ENTRYPOINT ["/usr/src/app/docker-entrypoint.sh"]

FROM

FROM [repository]/[image]:[version]

這裡指的是我們的Dockerfile所要使用的基礎image為何,基本上我們所撰寫的Dockerfile都會以一個image為基礎迭代而成。由於筆者較偏好於ubuntu作業系統,因此選定該image為base image。

WORKDIR

WORKDIR [path]

這邊是用來設定Container內的預設工作路徑,類似於Linux的~。

COPY

COPY [file_path] [container_path]

複製本地路徑的file到Container內,這邊我們是將整個web service的所有程式都複製進去。

ENV

ENV [key] [value]

設定環境變數 PYTHONUNBUFFERED為1,此環境變數為python log所使用。可依自己喜好給env variable,之後也會教如何去設定整個檔案的變數為Container的環境變數。

RUN

RUN [command]

在container內執行commands,這邊筆者是在ubuntu的container內

  1. 安裝python3與相關的packages
  2. 更新 pip tool
  3. 利用pip 安裝 python packages

EXPOSE

EXPOSE [port]

Container所要暴露的port,這邊筆者是暴露flask內所啟動的8100port,如此一來目前我們就能透過docker-network來找到container的8100 port。

ENTRYPOINT

ENTRYPOINT [command] [params1] [params2]

ENTRYPOINT ["executable", [params1], [params2]]

這邊Entrypoint指令可以支援兩種不同格式,分別是為了直接下command以及執行執行檔

Entrypoint為Dockerfile所定義的指令,指的是在Container啟動時所會自動執行的指令,每個 Dockerfile 中只能有一個 ENTRYPOINT,當指定多個時,只有最後一個會生效。 這裡筆者是用來執行我們的shell script,用來啟動flask web service指令。

Create Image by Dockerfile

docker build -t [image_name] [path]

$ docker build -t ironman .

Start Container by Docker image

docker run [image_name]

這邊我們加上了幾個arguments

  • -name: 指定container name
  • d: 在背景運行
  • p: 將container所暴露的port綁定至localhost的port,如果不加上這一行,我們只能夠透過docker-network來與web service溝通。後面也會教如何設定你的docker network,敬請期待。
$ docker run --name ironman -d -p 8100:8100 ironman

Other commands in Dockerfile

User

運行Container時的使用者名稱或UID,後續運行Container也會使用該使用者。

ONBUILD

當你建立起的image,讓其他Image當做基底時,會在最後執行ONBUILD的COMMAND

,就等於是你的image讓人使用時會再多執行onbuild指令。

ADD

複製相對路徑的file至Container內,他同時也能接受URL或是tar檔案,但tar檔在複製後會自動解壓縮。

CMD

CMD [command] [params1] [params2]
CMD ["executable", [params1], [params2]]

CMD [[params1], [params2]]

有點類似於Entrypoint,但還是有著些許不同。

  1. 當有多個CMD時,只執行最後一條CMD
  2. 由CMD執行指令時的參數,能經由docker run帶入,帶Entrypoint不行。
  3. 當CMD執行時沒有帶入執行指令或執行檔,則視為Entrypoint的參數
  4. 當沒有Entrypoint但有CMD時,CMD會被視為是Entrypoint
  5. Entrypoint優先前高於CMD

Github Repo

本篇章所有程式碼將放在下面的github project當中的branch day-5

https://github.com/Neskem/ironman_2020/tree/day-5

往後該系列的展示程式碼,都將放在同一project並以不同branch的形式提供參考。

小結

本篇章透過簡單的python code來展示如何將自己的web service包在Dockerfile之中,
希望能夠拋磚引玉,讓各位讀者嘗試打包自己的服務。也恭喜大家學會了撰寫自己的Dockerfile,讓自己在容器化技術上獲得了一項強力武器!!

https://ithelp.ithome.com.tw/upload/images/20200920/201297379Q0khrxTBh.png

Reference

https://docs.docker.com/develop/develop-images/dockerfile_best-practices/


上一篇
Day-4 初出Docker
下一篇
Day-6 乘載 Docker Image的靈魂 Docker Hub & Github Packages
系列文
Docker獸 究極進化 ~~ Kubernetes獸30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
brucetasy
iT邦新手 5 級 ‧ 2020-10-29 11:33:56

您好: 目前依據您的做學習中
想請問 命令 粗體字代表意義 ?
$ docker run --name ironman -d -p 8100:8100 ironman

docker run --name <container_name> -d -p 8100:8100 <image_name>

brucetasy iT邦新手 5 級 ‧ 2020-11-04 09:54:12 檢舉

感謝

我要留言

立即登入留言